#pragma once
#include <iostream>
#include <unordered_map>
#include <vector>
#include <string>
#include "../mqcommon/Helper.hpp"
#include "../mqcommon/Log.hpp"
#include "../mqcommon/msg.pb.h"
using namespace std;
namespace mq
{
    class Binding
    {
    public:
        using BindingPtr = shared_ptr<Binding>;
        Binding() {}
        Binding(const string &exchange_name, const string &msgqueue_name, const string &binding_key)
            : _exchange_name(exchange_name), _msgqueue_name(msgqueue_name), _binding_key(binding_key)
        {
        }

    public:
        string _exchange_name;
        string _msgqueue_name;
        string _binding_key;
    };

    class BindingMapper
    {
    public:
        // 队列 ---> 绑定信息
        using MsgQueueBindingMap = unordered_map<string, Binding::BindingPtr>;
        // 交换机 ---> (队列, 绑定信息)
        using BindingMap = unordered_map<string, MsgQueueBindingMap>;
        BindingMapper(const string &dbname) : _sql_helper(dbname)
        {
            string dir = mq::FileHelper::parentDirectory(dbname);
            mq::FileHelper::createDirectory(dir);
            assert(_sql_helper.open());
            createTable();
        }
        ~BindingMapper()
        {
            _sql_helper.close();
        }
        // 创建绑定关系表
        void createTable()
        {
            string sql = "create table if not exists binding_table(\
            exchange_name varchar(32),\
            queue_name varchar(32),\
            binding_key varchar(128));";
            if (_sql_helper.exec(sql, nullptr, nullptr) == false)
            {
                DLOG("数据库表创建失败");
                abort();
            }
        }
        // 删除绑定关系表
        void removeTable()
        {
            string sql = "drop table binding_table;";
            if (_sql_helper.exec(sql, nullptr, nullptr) == false)
            {
                DLOG("数据库表删除失败");
                abort();
            }
        }
        // 向表中插入绑定关系
        bool insert(Binding::BindingPtr &binding)
        {
            stringstream ss;
            ss << "insert into binding_table values(";
            ss << "'" << binding->_exchange_name << "',";
            ss << "'" << binding->_msgqueue_name << "',";
            ss << "'" << binding->_binding_key << "');";
            return _sql_helper.exec(ss.str(), nullptr, nullptr);
        }
        // 从表中移除绑定关系
        void remove(const std::string &ename, const std::string &qname)
        {
            stringstream ss;
            ss << "delete from binding_table where exchange_name=";
            ss << "'" << ename << "', queue_name=";
            ss << "'" << qname << "';";
            _sql_helper.exec(ss.str(), nullptr, nullptr);
        }
        // 从表中移除与交换机相关的绑定关系
        void removeExchangeBindings(const std::string &ename)
        {
            stringstream ss;
            ss << "delete from binding_table where exchange_name=";
            ss << "'" << ename << "';";
            _sql_helper.exec(ss.str(), nullptr, nullptr);
        }
        // 从表中移除与队列相关的绑定关系
        void removeMsgQueueBindings(const std::string &qname)
        {
            stringstream ss;
            ss << "delete from binding_table where queue_name=";
            ss << "'" << qname << "';";
            _sql_helper.exec(ss.str(), nullptr, nullptr);
        }
        // 从持久化文件恢复
        BindingMap recovery()
        {
            BindingMap result;
            string sql = "select exchange_name, queue_name, binding_key from binding_table;";
            if (_sql_helper.exec(sql.c_str(), selectCallback, &result) == false)
            {
                DLOG("数据库表查询失败");
                abort();
            }
            return result;
        }

    private:
        static int selectCallback(void *arg, int numcol, char **row, char **fields)
        {
            BindingMap *result = static_cast<BindingMap *>(arg);
            auto bmp = make_shared<Binding>();
            bmp->_exchange_name = row[0];
            bmp->_msgqueue_name = row[1];
            bmp->_binding_key = row[2];
            auto &mbm = (*result)[bmp->_exchange_name];
            mbm.insert(make_pair(bmp->_msgqueue_name, bmp));
            return 0;
        }

    private:
        mq::SqliteHelper _sql_helper;
    };
    class BindingManager
    {
    public:
        // 队列 ---> 绑定信息
        using MsgQueueBindingMap = unordered_map<string, Binding::BindingPtr>;
        // 交换机 ---> (队列, 绑定信息)
        using BindingMap = unordered_map<string, MsgQueueBindingMap>;
        using BindingManagerPtr = shared_ptr<BindingManager>;
        BindingManager(const string &dbname) : _mappers(dbname)
        {
            _bindings = _mappers.recovery();
        }
        // 绑定交换机和队列并根据参数进行持久化
        bool bind(const std::string &ename, const std::string &qname, const std::string &key, bool durable)
        {
            unique_lock<mutex> lock(_mutex);
            auto eit = _bindings.find(ename);
            if (eit != _bindings.end() && eit->second.find(qname) != eit->second.end())
            {
                return true;
            }
            Binding::BindingPtr binding = make_shared<Binding>(ename, qname, key);
            if (durable == true)
            {
                if (_mappers.insert(binding) == false)
                {
                    DLOG("绑定关系持久化写入失败:%s -> %s", ename.c_str(), qname.c_str());
                    return false;
                }
            }

            auto &um = _bindings[ename];
            um.insert(make_pair(qname, binding));
            return true;
        }
        // 解除交换机和队列的绑定关系
        void unBind(const std::string &ename, const std::string &qname)
        {
            unique_lock<mutex> lock(_mutex);
            auto eit = _bindings.find(ename);
            if (eit == _bindings.end())
            {
                DLOG("无法找到目标交换机:%s", ename.c_str());
                return;
            }
            auto qit = eit->second.find(qname);
            if (qit == eit->second.end())
            {
                DLOG("无法找到目标队列:%s", qname.c_str());
                return;
            }
            _mappers.removeMsgQueueBindings(qname);
            _bindings[ename].erase(qname);
        }
        // 移除与交换机相关的所有绑定关系
        void removeExchangeBindings(const std::string &ename)
        {
            unique_lock<mutex> lock(_mutex);
            auto eit = _bindings.find(ename);
            if (eit == _bindings.end())
                return;
            _mappers.removeExchangeBindings(ename);
            _bindings.erase(ename);
        }
        // 移除与队列相关的所有绑定关系
        void removeMsgQueueBindings(const std::string &qname)
        {
            unique_lock<mutex> lock(_mutex);
            _mappers.removeMsgQueueBindings(qname);
            for (auto &eit : _bindings)
            {
                eit.second.erase(qname);
            }
        }
        // 根据交换机获取该交换机中所有队列的绑定关系（队列——>绑定关系）
        MsgQueueBindingMap getExchangeBindings(const std::string &ename)
        {
            unique_lock<mutex> lock(_mutex);
            auto eit = _bindings.find(ename);
            if (eit == _bindings.end())
                return MsgQueueBindingMap();
            return eit->second;
        }
        // 获取指定交换机和队列的绑定关系
        Binding::BindingPtr getBinding(const std::string &ename, const std::string &qname)
        {
            unique_lock<mutex> lock(_mutex);
            auto eit = _bindings.find(ename);
            if (eit == _bindings.end())
                return Binding::BindingPtr();
            auto qit = eit->second.find(qname);
            if (qit == eit->second.end())
                return Binding::BindingPtr();
            return qit->second;
        }
        // 判断交换机和队列是否存在绑定关系
        bool exists(const std::string &ename, const std::string &qname)
        {
            unique_lock<mutex> lock(_mutex);
            auto eit = _bindings.find(ename);
            if (eit == _bindings.end())
                return false;
            auto qit = eit->second.find(qname);
            if (qit == eit->second.end())
                return false;
            return true;
        }
        // 获取交换机上所有的绑定关系数量
        size_t size()
        {
            unique_lock<mutex> lock(_mutex);
            size_t size = 0;
            for (auto &it : _bindings)
            {
                size += it.second.size();
            }
            return size;
        }
        // 清除交换机中所有绑定关系
        void clear()
        {
            unique_lock<mutex> lock(_mutex);
            _mappers.removeTable();
            _bindings.clear();
        }

    private:
        mutex _mutex;
        BindingMapper _mappers; // 绑定关系持久化句柄
        BindingMap _bindings;   // 交换机 ---> (队列, 绑定信息)
    };
}